try:
    import psyco; psyco.full()
except: pass

import sys

try: __import__('_prepscript_util', globals(), locals(), [], -1)
except ImportError:
    raise SystemError("add the quartet's directory to the PYTHONPATH")

from _prepscript_util import calc_md5
from _token_util import *
import cldt_datamanip as dm

__usage = """
Usage: cldt_tolinenum OPTIONS datafile
Option
  -o output: output file
"""[1:-1]

if __name__ == '__main__':
    maxint = sys.maxint
    
    dataFileName = None
    outputFileName = None
    
    if len(sys.argv) == 1:
        print __usage
        sys.exit(0)
    i = 1
    while i < len(sys.argv):
        arg = sys.argv[i]
        if arg.startswith("-") and arg != "-":
            if arg == "-h":
                print __usage
                sys.exit(0)
            elif arg == "-o":
                outputFileName = sys.argv[i + 1]
                i += 1
            else:
                raise SystemError("unknown option: %s" % arg)
        else:
            if not dataFileName:
                dataFileName = arg
            else:
                raise SystemError("too many command-line arguments")
        i += 1
    
    outputFile = open(outputFileName, "w") if outputFileName else sys.stdout
    output_write = outputFile.write
    
    def commentSink(comment):
        output_write("%s\n" % comment)
    
    filePathTable = dict()
    fileChecksumTable = dict()
    def fileSink(fileID, pathStr, length, checksumStr):
        filePathTable[fileID] = pathStr
        fileChecksumTable[fileID] = checksumStr
    
    fileContentTable = dict()
    def build_file_contents():
        assert filePathTable
        output_write("#cldt_tolinenum\n")
        
        for fileID, pathStr in sorted(filePathTable.iteritems()):
            #lineCount = 0
            #f = file(pathStr)
            #for line in f:
            #    lineCount += 1
            #f.close()
            
            tokenIndexToLinenumTable = []; a = tokenIndexToLinenumTable.append
            prepPathStr = pathStr + ".prep"
            f = file(prepPathStr)
            for L in f:
                if not L or L[0] == '#': continue
                L = L[:L.index("\t")]
                a(int(L[:L.index(",")]) if L else None)
            f.close()
            if calc_md5(prepPathStr) != fileChecksumTable[fileID]:
                raise SystemError, "checksum mismatch for a preprocessed file (perhaps clonedata is obsolute): %s" % prepPathStr
            
            fileContentTable[fileID] = tokenIndexToLinenumTable
        def fileLargestLineNum(fileID):
            lineNums = fileContentTable[fileID] 
            for n in reversed(fileContentTable[fileID]):
                if n is not None: return n
            else: return 0
        
        output_write("files:\n")
        for fileID, path in sorted(filePathTable.iteritems()):
            output_write("%d\t%s\t%d\t%s\n" % ( fileID, path, fileLargestLineNum(fileID), fileChecksumTable[fileID] ))
        output_write("clone classes:\n")
    
    def cloneSink(cloneClass):
        if not fileContentTable:
            build_file_contents()
        output_write("{\n")
        for csi, cloneSubclass in enumerate(cloneClass):
            if csi > 0:
                output_write("--\n")
            for fileID, positions in cloneSubclass:
                tokenIndexToLinenumTable = fileContentTable[fileID]
                len_tokenIndexToLinenumTable = len(tokenIndexToLinenumTable)
                lineNumSet = set()
                for beginPos, length in positions:
                    if beginPos + length == len_tokenIndexToLinenumTable + 1:
                        length -= 1
                    if length > 0:
                        lineNumSet.update(map(tokenIndexToLinenumTable.__getitem__, xrange(beginPos, beginPos + length)))
                lineNumSet.discard(None)
                output_write("%d\t%s\n" % ( fileID, ",".join("%d+%d" % ( r[0], r[1] - r[0] ) for r in indices_to_ranges(sorted(lineNumSet))) ))
        output_write("}\n")
    
    dataFile = open(dataFileName) if dataFileName != '-' else sys.stdin
    dm.scan_clone_data_file(dataFile, commentSink, fileSink, cloneSink)
    if dataFile is not sys.stdin: dataFile.close()
    
    if outputFile is not sys.stdout: outputFile.close()
